"""
Basic widgets for VN Trader.
"""

import csv
import platform
from enum import Enum
from typing import Any, Dict
from copy import copy

from tzlocal import get_localzone
from pathlib import Path
from datetime import datetime
import json

from PyQt5 import QtCore, QtGui, QtWidgets, Qt
from PyQt5.QtWidgets import QHeaderView
import rqdatac
import numpy as np

import vnpy
import vnsumscope
from vnsumscope import event
from vnsumscope.event import Event, EventEngine
from vnsumscope.trader.ui import editor
from vnsumscope.trader.ui.editor import CodeEditor
from ..constant import Direction, Exchange, Offset, OrderType
from ..engine import MainEngine
from ..event import (
    EVENT_TICK,
    EVENT_TRADE,
    EVENT_ORDER,
    EVENT_POSITION,
    EVENT_ACCOUNT,
    EVENT_LOG
)
from ..object import OrderRequest, SubscribeRequest, PositionData
from ..utility import load_json, save_json, VNSUMSCOPE_CTA_STRATEGY_DIR, VNSUMSCOPE_PORTFOLIO_STRATEGY_DIR
from ..setting import SETTING_FILENAME, SETTINGS

COLOR_LONG = QtGui.QColor("red")
COLOR_SHORT = QtGui.QColor("green")
COLOR_BID = QtGui.QColor(255, 174, 201)
COLOR_ASK = QtGui.QColor(160, 255, 160)
COLOR_BLACK = QtGui.QColor("black")


class BaseCell(QtWidgets.QTableWidgetItem):
    """
    General cell used in tablewidgets.
    """

    def __init__(self, content: Any, data: Any):
        """"""
        super(BaseCell, self).__init__()
        self.setTextAlignment(QtCore.Qt.AlignCenter)
        self.content = content
        self.set_content(content, data)

    def set_content(self, content: Any, data: Any) -> None:
        """
        Set text content.
        """
        self.setText(str(content))
        self._data = data

    def get_data(self) -> Any:
        """
        Get data object.
        """
        return self._data

    def __hash__(self):
        return hash(self.content)


class EnumCell(BaseCell):
    """
    Cell used for showing enum data.
    """

    def __init__(self, content: str, data: Any):
        """"""
        super(EnumCell, self).__init__(content, data)

    def set_content(self, content: Any, data: Any) -> None:
        """
        Set text using enum.constant.value.
        """
        if isinstance(content, str):
            super(EnumCell, self).set_content(content, data)
        else:
            super(EnumCell, self).set_content(content.value, data)


class DirectionCell(EnumCell):
    """
    Cell used for showing direction data.
    """

    def __init__(self, content: str, data: Any):
        """"""
        super(DirectionCell, self).__init__(content, data)

    def set_content(self, content: Any, data: Any) -> None:
        """
        Cell color is set according to direction.
        """
        super(DirectionCell, self).set_content(content, data)

        if content is Direction.SHORT or content == Direction.SHORT.value:
            self.setForeground(COLOR_SHORT)
        else:
            self.setForeground(COLOR_LONG)


class BidCell(BaseCell):
    """
    Cell used for showing bid price and volume.
    """

    def __init__(self, content: Any, data: Any):
        """"""
        super(BidCell, self).__init__(content, data)

        self.setForeground(COLOR_BID)


class AskCell(BaseCell):
    """
    Cell used for showing ask price and volume.
    """

    def __init__(self, content: Any, data: Any):
        """"""
        super(AskCell, self).__init__(content, data)

        self.setForeground(COLOR_ASK)


class PnlCell(BaseCell):
    """
    Cell used for showing pnl data.
    """

    def __init__(self, content: Any, data: Any):
        """"""
        super(PnlCell, self).__init__(content, data)

    def set_content(self, content: Any, data: Any) -> None:
        """
        Cell color is set based on whether pnl is
        positive or negative.
        """
        super(PnlCell, self).set_content(content, data)

        if str(content).startswith("-"):
            self.setForeground(COLOR_SHORT)
        else:
            self.setForeground(COLOR_LONG)


class TimeCell(BaseCell):
    """
    Cell used for showing time string from datetime object.
    """

    local_tz = get_localzone()

    def __init__(self, content: Any, data: Any):
        """"""
        super(TimeCell, self).__init__(content, data)

    def set_content(self, content: Any, data: Any) -> None:
        """"""
        if content is None:
            return

        content = content.astimezone(self.local_tz)
        timestamp = content.strftime("%Y-%m-%d %H:%M:%S")

        millisecond = int(content.microsecond / 1000)
        if millisecond:
            timestamp = f"{timestamp}.{millisecond}"

        self.setText(timestamp)
        self._data = data


class MsgCell(BaseCell):
    """
    Cell used for showing msg data.
    """

    def __init__(self, content: str, data: Any):
        """"""
        super(MsgCell, self).__init__(content, data)
        self.setTextAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)


class ButtonType(Enum):
    """"""
    RECORDS = '查看记录'
    RUN = '运行'
    EDIT = '编辑'
    DELETE = '删除'


class TemplateType(Enum):
    """"""
    CTA = 'CTA策略'
    PORTFOLIO = 'PORTFOLIO策略'


class BaseMonitor(QtWidgets.QTableWidget):
    """
    Monitor data update in VN Trader.
    """

    event_type: str = ""
    data_key: str = ""
    sorting: bool = False
    headers: Dict[str, dict] = {}

    signal: QtCore.pyqtSignal = QtCore.pyqtSignal(Event)

    def __init__(self, main_engine: MainEngine, event_engine: EventEngine):
        """"""
        super(BaseMonitor, self).__init__()

        self.main_engine: MainEngine = main_engine
        self.event_engine: EventEngine = event_engine
        self.cells: Dict[str, dict] = {}

        self.init_ui()
        self.load_setting()
        self.register_event()

    def __del__(self) -> None:
        """"""
        self.save_setting()

    def init_ui(self) -> None:
        """"""
        self.init_table()
        self.init_menu()

    def init_table(self) -> None:
        """
        Initialize table.
        """
        self.setColumnCount(len(self.headers))

        labels = [d["display"] for d in self.headers.values()]
        self.setHorizontalHeaderLabels(labels)

        self.verticalHeader().setVisible(False)
        self.setEditTriggers(self.NoEditTriggers)
        self.setAlternatingRowColors(True)
        self.setSortingEnabled(self.sorting)

    def init_menu(self) -> None:
        """
        Create right click menu.
        """
        self.menu = QtWidgets.QMenu(self)

        resize_action = QtWidgets.QAction("调整列宽", self)
        resize_action.triggered.connect(self.resize_columns)
        self.menu.addAction(resize_action)

        save_action = QtWidgets.QAction("保存数据", self)
        save_action.triggered.connect(self.save_csv)
        self.menu.addAction(save_action)

    def register_event(self) -> None:
        """
        Register event handler into event engine.
        """
        if self.event_type:
            self.signal.connect(self.process_event)
            self.event_engine.register(self.event_type, self.signal.emit)

    def process_event(self, event: Event) -> None:
        """
        Process new data from event and update into table.
        """
        # Disable sorting to prevent unwanted error.
        if self.sorting:
            self.setSortingEnabled(False)

        # Update data into table.
        data = event.data

        if not self.data_key:
            self.insert_new_row(data)
        else:
            key = data.__getattribute__(self.data_key)

            if key in self.cells:
                self.update_old_row(data)
            else:
                self.insert_new_row(data)

        # Enable sorting
        if self.sorting:
            self.setSortingEnabled(True)

    def insert_new_row(self, data: Any):
        """
        Insert a new row at the top of table.
        """
        self.insertRow(0)
        row_cells = {}
        for column, header in enumerate(self.headers.keys()):
            setting = self.headers[header]

            content = data.__getattribute__(header)
            cell = setting["cell"](content, data)
            self.setItem(0, column, cell)

            if setting["update"]:
                row_cells[header] = cell

        if self.data_key:
            key = data.__getattribute__(self.data_key)
            self.cells[key] = row_cells

    def update_old_row(self, data: Any) -> None:
        """
        Update an old row in table.
        """
        key = data.__getattribute__(self.data_key)
        row_cells = self.cells[key]

        for header, cell in row_cells.items():
            content = data.__getattribute__(header)
            cell.set_content(content, data)

    def resize_columns(self) -> None:
        """
        Resize all columns according to contents.
        """
        self.horizontalHeader().resizeSections(QtWidgets.QHeaderView.ResizeToContents)

    def save_csv(self) -> None:
        """
        Save table data into a csv file
        """
        path, _ = QtWidgets.QFileDialog.getSaveFileName(
            self, "保存数据", "", "CSV(*.csv)")

        if not path:
            return

        with open(path, "w") as f:
            writer = csv.writer(f, lineterminator="\n")

            headers = [d["display"] for d in self.headers.values()]
            writer.writerow(headers)

            for row in range(self.rowCount()):
                if self.isRowHidden(row):
                    continue

                row_data = []
                for column in range(self.columnCount()):
                    item = self.item(row, column)
                    if item:
                        row_data.append(str(item.text()))
                    else:
                        row_data.append("")
                writer.writerow(row_data)

    def contextMenuEvent(self, event: QtGui.QContextMenuEvent) -> None:
        """
        Show menu with right click.
        """
        self.menu.popup(QtGui.QCursor.pos())

    def save_setting(self) -> None:
        """"""
        settings = QtCore.QSettings(self.__class__.__name__, "custom")
        # settings.setValue("column_state", self.horizontalHeader().saveState())

    def load_setting(self) -> None:
        """"""
        # settings = QtCore.QSettings(self.__class__.__name__, "custom")
        # column_state = settings.value("column_state")

        # if isinstance(column_state, QtCore.QByteArray):
        #     self.horizontalHeader().restoreState(column_state)
        #     self.horizontalHeader().setSortIndicator(-1, QtCore.Qt.AscendingOrder)


class OptimizationResultsDialog(BaseMonitor):
    def insert_new_row_option(self, data: Any):
        """
        Insert a new row at the top of table.
        """
        self.init_table()
        self.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)

        for index,option_data in enumerate(data):
            self.insertRow(0)
            row_cells = {}
            for column, header in enumerate(self.headers.keys()):
                setting = self.headers[header]
                content = option_data.get(header)

                cell = setting["cell"](content, option_data)
                self.setItem(0, column, cell)

                if setting["update"]:
                    row_cells[header] = cell


class StrategyMonitor(BaseMonitor):
    """
    Monitor for order data.
    """
    data_key = "strategy_file"
    sorting = True

    headers: Dict[str, dict] = {

        "strategy_file": {"display": "策略文件", "cell": BaseCell, "update": False},
        "strategy_type": {"display": "策略类型", "cell": BaseCell, "update": False},
        "edit": {"display": "编辑策略", "cell": BaseCell, "update": False},
        "run": {"display": "运行回测", "cell": BaseCell, "update": False},
        "create_time": {"display": "创建时间", "cell": BaseCell, "update": False},
        "modify_time": {"display": "修改时间", "cell": BaseCell, "update": False},
        "records": {"display": "回测记录", "cell": BaseCell, "update": False},
    }

    def init_ui(self):
        """
        Connect signal.
        """
        super(StrategyMonitor, self).init_ui()


class BuiltinStrategyMonitor(StrategyMonitor):
    """
    Monitor which shows active order only.
    """
    strategies_path = f'{vnsumscope.__path__[0]}'
    cta_dir = Path(strategies_path).joinpath('app', 'cta_strategy', 'strategies')
    portfolio_dir = Path(strategies_path).joinpath('app', 'portfolio_strategy', 'strategies')

    def init_table(self):
        # 内建策略不显示删除
        if 'delete' in self.headers:
            self.headers.pop('delete')
        super(BuiltinStrategyMonitor, self).init_table()

        for p in [self.cta_dir, self.portfolio_dir]:
            files = p.glob('*.py')
            for f in files:
                if '__init__' in f.name:
                    continue
                strategy_path = str(f)
                self.insert_new_row(strategy_path)
        self.resize_columns()

    def insert_new_row(self, data: Any, resize: bool=False):
        """
        Insert a new row at the top of table.
        """
        self.insertRow(0)
        f = Path(data)
        strategy_path = str(f)
        if f.parent == self.cta_dir:
            template = TemplateType.CTA
        elif f.parent == self.portfolio_dir:
            template = TemplateType.PORTFOLIO
        data = {
            'strategy_file': BaseCell(str(f.name), str),
            'strategy_type': BaseCell(template.value, str),
            'create_time': TimeCell(datetime.fromtimestamp(int(f.stat().st_ctime)), str),
            'modify_time': TimeCell(datetime.fromtimestamp(int(f.stat().st_mtime)), str),
            'records': ButtonWidget(self.event_engine, ButtonType.RECORDS, strategy_path, template=template),
            'run': ButtonWidget(self.event_engine, ButtonType.RUN, strategy_path, template=template),
            'edit': ButtonWidget(self.event_engine, ButtonType.EDIT, strategy_path, template=template)
        }
        for column, header in enumerate(self.headers.keys()):
            content = data.get(header, None)
            cell = content
            if header == 'strategy_file':
                cell.setTextAlignment(QtCore.Qt.AlignLeft)
            if isinstance(cell, ButtonWidget):
                self.setCellWidget(0, column, cell)
            else:
                self.setItem(0, column, cell)
        if self.data_key:
            key = data.get(self.data_key, None)
            self.cells[key.content] = data
        if resize:
            self.resize_columns()


class SelfStrategyMonitor(StrategyMonitor):
    """
    Monitor which shows active order only.
    """
    create_event_type = 'create_strategy'
    delete_event_type = 'delete_strategy'
    sorting = True
    cta_strategies_path = VNSUMSCOPE_CTA_STRATEGY_DIR
    portfolio_strategies_path = VNSUMSCOPE_PORTFOLIO_STRATEGY_DIR
    create_signal: QtCore.pyqtSignal = QtCore.pyqtSignal(Event)
    delete_signal: QtCore.pyqtSignal = QtCore.pyqtSignal(Event)

    def init_table(self):
        if 'delete' not in self.headers:
            self.headers["delete"] = {"display": "删除策略", "cell": BaseCell, "update": False}
        super(SelfStrategyMonitor, self).init_table()
        for p in [self.cta_strategies_path, self.portfolio_strategies_path]:
            files = p.glob('*.py')
            for f in files:
                if '__init__' in f.name:
                    continue
                strategy_path = str(f)
                self.insert_new_row(strategy_path)
        self.resize_columns()

    def insert_new_row(self, data: Any, resize: bool=False):
        """
        Insert a new row at the top of table.
        """
        self.insertRow(0)
        f = Path(data)
        strategy_path = str(f)
        if f.parent == self.cta_strategies_path:
            template = TemplateType.CTA
        elif f.parent == self.portfolio_strategies_path:
            template = TemplateType.PORTFOLIO
        data = {
            'strategy_file': BaseCell(str(f.name), str),
            'strategy_type': BaseCell(template.value, str),
            'create_time': TimeCell(datetime.fromtimestamp(int(f.stat().st_ctime)), str),
            'modify_time': TimeCell(datetime.fromtimestamp(int(f.stat().st_mtime)), str),
            'records': ButtonWidget(self.event_engine, ButtonType.RECORDS, strategy_path, template=template),
            'run': ButtonWidget(self.event_engine, ButtonType.RUN, strategy_path, template=template),
            'edit': ButtonWidget(self.event_engine, ButtonType.EDIT, strategy_path, template=template),
            'delete': ButtonWidget(self.event_engine, ButtonType.DELETE, strategy_path, template=template)
        }
        for column, header in enumerate(self.headers.keys()):
            content = data.get(header, None)
            cell = content
            if header == 'strategy_file':
                cell.setTextAlignment(QtCore.Qt.AlignLeft)
            if isinstance(cell, ButtonWidget):
                self.setCellWidget(0, column, cell)
            else:
                self.setItem(0, column, cell)
        if self.data_key:
            key = data.get(self.data_key, None)
            self.cells[key.content] = data
        if resize:
            self.resize_columns()

    def register_event(self) -> None:
        """
        Register event handler into event engine.
        """
        self.create_signal.connect(self.process_create)
        self.event_engine.register(self.create_event_type, self.create_signal.emit)
        self.delete_signal.connect(self.process_delete)
        self.event_engine.register(self.delete_event_type, self.delete_signal.emit)

    def process_create(self, event) -> None:
        """
        Hides the row if order is not active.
        """
        self.insert_new_row(event.data, resize=True)

    def process_delete(self, event) -> None:
        self.delete_row(event.data)

    def delete_row(self, data: str):
        from vnsumscope.database.sqlite import records_manager
        row = self.indexAt(data['button'].pos()).row()
        p = Path(data['strategy_path'])
        strategy_id = p.stat().st_ino
        flag = records_manager.delete_records(strategy_id)
        if flag:
            self.removeRow(row)
            p.unlink()



class ButtonWidget(QtWidgets.QWidget):
    """将行信息和事件绑定到button上，便于查到表格对应的行打开对应窗口"""
    def __init__(self, event_engine: EventEngine, text, strategy_path, template=None, *args, **kwargs) -> None:
        super(ButtonWidget, self).__init__(*args, **kwargs)
        self.event_engine = event_engine
        self.text = text
        self._strategy_path = strategy_path
        self.template = template
        layout = QtWidgets.QHBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(QtWidgets.QPushButton(self.text.value, self, clicked=self.clicked_trigger))
        self.widgets: Dict[str, QtWidgets.QWidget] = {}


    def clicked_trigger(self) -> None:
        if self.text == ButtonType.RECORDS:
            self.view_records()
        elif self.text == ButtonType.RUN:
            self.open_app()
        elif self.text == ButtonType.EDIT:
            self.open_editor()
        elif self.text == ButtonType.DELETE:
            self.delete()

    def open_app(self) -> None:
        if self.template == TemplateType.CTA:
            self.open_cta_app()
        elif self.template == TemplateType.PORTFOLIO:
            self.open_portfolio_app()

    def open_cta_app(self) -> None:
        from vnsumscope.app.cta_backtester.ui import BacktesterManager
        self.open_widget(BacktesterManager, 'CTA回测')

    def open_portfolio_app(self) -> None:
        from vnsumscope.app.portfolio_backtester.ui import PortfolioManager
        self.open_widget(PortfolioManager, '组合回测')
        # QtWidgets.QMessageBox.information(self, '提示', '组合策略模块尚未开放', QtWidgets.QMessageBox.Yes)

    def view_records(self) -> None:
        from vnsumscope.app.backtest_records.ui import BacktestRecordsManager
        self.open_widget_records(BacktestRecordsManager, '回测记录')


    def open_editor(self) -> None:
        editor = CodeEditor()
        editor.open_editor(self._strategy_path)

    def delete(self) -> None:
        p = Path(self._strategy_path)
        box = QtWidgets.QMessageBox()
        box.setIcon(QtWidgets.QMessageBox.Question)
        box.setWindowTitle('删除策略')
        box.setText(
            f'删除策略{p.name}?\n\n'
            '注意：\n'
            '确认后该策略会被彻底删除\n'
            '包括策略文件和运行记录!'
        )
        box.setStyleSheet("QLabel{ color: red}")
        box.setStandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
        self.button_y = box.button(QtWidgets.QMessageBox.Yes)
        self.button_y.setEnabled(False)
        self.count = 5
        self.button_y.setText(f'确定{self.count}')
        self.time = QtCore.QTimer(self)
        self.time.setInterval(1000)
        self.time.timeout.connect(self.time_refresh)
        self.time.start()
        self.button_n = box.button(QtWidgets.QMessageBox.No)
        self.button_n.setText("取消")
        box.exec_()
        if box.clickedButton() == self.button_y:
            self.event_engine.put(
                Event('delete_strategy', {'strategy_path': self._strategy_path, 'button': self})
            )
        elif box.clickedButton() == self.button_y:
            self.time.stop()
        if box.close():
            self.time.stop()

    def time_refresh(self):
        if self.count > 1:
            self.count -= 1
            self.button_y.setText(f'确定{self.count}')
        else:
            self.time.stop()
            self.button_y.setEnabled(True)
            self.button_y.setText('确定')

    def open_widget(self, widget_class: QtWidgets.QWidget, name: str) -> None:
        """
        Open contract manager.
        """
        from vnsumscope.event import EventEngine
        from vnsumscope.trader.engine import MainEngine

        from vnsumscope.app.cta_backtester import CtaBacktesterApp
        from vnsumscope.app.portfolio_backtester import PortfolioBacktesterApp

        event_engine = EventEngine()
        main_engine = MainEngine(event_engine)
        if name == "CTA回测":
            main_engine.add_app(CtaBacktesterApp)
        else:
            main_engine.add_app(PortfolioBacktesterApp)
        widget = widget_class(main_engine, event_engine, self._strategy_path)
        self.widgets[name] = widget

        if isinstance(widget, QtWidgets.QDialog):
            widget.exec_()
        else:
            widget.show()


    def open_widget_records(self, widget_class: QtWidgets.QWidget, name: str) -> None:
        """
        Open contract manager.
        """
        widget = widget_class(self._strategy_path)
        self.widgets[name] = widget
        if isinstance(widget, QtWidgets.QDialog):
            widget.exec_()
        else:
            widget.show()


class AboutDialog(QtWidgets.QDialog):
    """
    About VN Trader.
    """

    def __init__(self, main_engine: MainEngine, event_engine: EventEngine):
        """"""
        super().__init__()

        self.main_engine: MainEngine = main_engine
        self.event_engine: EventEngine = event_engine

        self.init_ui()

    def init_ui(self) -> None:
        """"""
        self.setWindowTitle(f"关于VN Trader")

        text = f"""
            By Traders, For Traders.


            License：MIT
            Website：www.vnpy.com
            Github：www.github.com/vnpy/vnpy

            vnsumscope - {vnsumscope.__version__}

            vn.py - {vnpy.__version__}
            Python - {platform.python_version()}
            PyQt5 - {Qt.PYQT_VERSION_STR}
            Numpy - {np.__version__}
            RQData - {rqdatac.__version__}
            """

        label = QtWidgets.QLabel()
        label.setText(text)
        label.setMinimumWidth(500)

        vbox = QtWidgets.QVBoxLayout()
        vbox.addWidget(label)
        self.setLayout(vbox)


class GlobalDialog(QtWidgets.QDialog):
    """
    Start connection of a certain gateway.
    """

    def __init__(self):
        """"""
        super().__init__()

        self.widgets: Dict[str, Any] = {}

        self.init_ui()

    def init_ui(self) -> None:
        """"""
        self.setWindowTitle("全局配置")
        self.setMinimumWidth(800)

        settings = copy(SETTINGS)
        settings.update(load_json(SETTING_FILENAME))

        # Initialize line edits and form layout based on setting.
        form = QtWidgets.QFormLayout()

        for field_name, field_value in settings.items():
            if 'log.' in field_name or 'rqdata.' in field_name:
                continue
            field_type = type(field_value)
            widget = QtWidgets.QLineEdit(str(field_value))
            if field_name == 'editor':
                editor_button = QtWidgets.QPushButton("选择策略编辑器")
                editor_button.clicked.connect(self.select_file)
                self.widget_editor = QtWidgets.QLineEdit()
                self.widget_editor.setPlaceholderText('填入策略编辑器的exe地址, 如：C:\\\\PyCharm\\\\pycharm.exe')
                self.widget_editor.setText(field_value)
                form.addRow(editor_button, self.widget_editor)
                self.widgets[field_name] = (self.widget_editor, field_type)
                continue
            form.addRow(f"{field_name} <{field_type.__name__}>", widget)
            self.widgets[field_name] = (widget, field_type)

        button = QtWidgets.QPushButton("确定")
        button.clicked.connect(self.update_setting)
        form.addRow(button)

        scroll_widget = QtWidgets.QWidget()
        scroll_widget.setLayout(form)

        scroll_area = QtWidgets.QScrollArea()
        scroll_area.setWidgetResizable(True)
        scroll_area.setWidget(scroll_widget)

        vbox = QtWidgets.QVBoxLayout()
        vbox.addWidget(scroll_area)
        self.setLayout(vbox)

    def select_file(self):
        """"""
        result: str = QtWidgets.QFileDialog.getOpenFileName(
            # self, filter="EXE (*.exe)")
            self, filter="All Files (*)")
        filename = result[0]
        if filename:
            self.widget_editor.setText(filename)

    def update_setting(self) -> None:
        """
        Get setting value from line edits and update global setting file.
        """
        settings = {}
        for field_name, tp in self.widgets.items():
            widget, field_type = tp
            value_text = widget.text()

            if field_type == bool:
                if value_text == "True":
                    field_value = True
                else:
                    field_value = False
            else:
                field_value = field_type(value_text)

            settings[field_name] = field_value

        QtWidgets.QMessageBox.information(
            self,
            "注意",
            "全局配置的修改需要重启后才会生效！",
            QtWidgets.QMessageBox.Ok
        )

        save_json(SETTING_FILENAME, settings)
        self.accept()
